//
// Created by tcj on 2022/2/24.
//

#ifndef _SYLAR_SCHEDULER_H__
#define _SYLAR_SCHEDULER_H__

//协程调度器，管理协程的调度，内部实现为一个线程池，支持协程在多线程中切换，
//也可以指定协程在固定线程中执行，是一个N-M的协程调度模型，N个线程，M个协程
//重复利用每一个线程


/*
 * 调度器内部维护一个任务队列和一个调度线程池，，
 *      开始调度后，线程池从任务队列中按顺序取任务执行。调度线程可以包含caller线程
 *          caller线程就是调度器的线程
 *       当全部任务都执行完成之后，线程池停止调度，等新任务进入
 *       添加新任务后，通知线程池有新任务进来了，线程池重新开始调度
 *       停止调度时，各调度线程退出，调度器停止工作
*
 *
 *
 * */

//class ptr;
//
//class ptr;
//协程调度器封装
#include "memory"
#include "fiber.h"
#include "thread.h"
#include "vector"
#include "list"
#include "iostream"
using namespace std;
namespace  sylar{
//    协程器调度：封装的是一个N-M的协程调度器
//    内部有一个线程池，支持协程在线程池中切换

//   协程调度器就是  首先将要调度的协程传递给调度器，然后调度器
//        负责将这些协程依次消耗
    class Scheduler{
    public:
        typedef std::shared_ptr<Scheduler> ptr;
        typedef Mutex MutexType;

        /*
         * 构造函数
         * threads:线程数量
         * use_caller:是否使用当前线程调用协程
         * name:协程调度器名称
         *
         * */
        Scheduler(size_t threads=1,bool use_caller =true,const std::string& name="");
        virtual ~Scheduler();

//       返回协程调度器名称
        const std::string& getName() const{return m_name;}
//返回当前协程调度器
        static Scheduler *GetThis();
//        返回当前协程调度器的调度协程
        static Fiber *GetMinFiber();

//        启动协程调度器
        void start();
//        停止协程调度器
        void stop();

//        调度协程
//    fc:协程或者是函数
//thread:协程执行的线程id,-1标识任意线程
        template<class FiberOrCb>
        void schedule(FiberOrCb fc,int thread=-1){
            std::cout<<"strat add schedule"<<std::endl;
            bool need_tickle = false;
            {
                MutexType::Lock lock(m_mutex);
                need_tickle = scheduleNoLock(fc,thread);
            }

            if(need_tickle){
                tickle();
            }
        }

//      批量调度协程
//begin:协程数组的开始
//end：协程数组的结束
        template<class InputIterator>
        void schedule(InputIterator begin,InputIterator end){
            bool need_tickle = false;
            {
                MutexType::Lock lock(m_mutex);
                while(begin != end){
                    need_tickle = scheduleNoLock(&*begin,-1) || need_tickle;
                    ++begin;
                }
            }

            if(need_tickle){
                tickle();
            }
        }

    protected:
//       通知线程调度器有任务了
        virtual void tickle();
//        协程调度函数
        void run();
//        返回是否可以停止
        virtual bool stopping();
//        协程无任务可调度时,可执行idle协程
        virtual void idle();
//设置当前协程调度器
        void SetThis();

        bool hasIdleThreads(){return m_idleThreadCount>0;}
    private:
//        协程调度启动(无锁)
        template<class FiberOrCb>
        bool scheduleNoLock(FiberOrCb fc,int thread){
            bool need_tickle = m_fibers.empty();
            FIberAndThread ft(fc,thread);
            if(ft.fiber || ft.cb){
                m_fibers.push_back(ft);
            }
            return need_tickle;
        }
    private:
//
        struct FIberAndThread{
//          协程
            Fiber::ptr fiber;
//          协程执行函数
            std::function<void()> cb;
//            线程id
            int thread;

//          构造函数,f:协程,thr:线程id
            FIberAndThread(Fiber::ptr f,int thr)
                :fiber(f),thread(thr){
            }
//          构造函数,f:协程指针,thr:线程id
//            post_state--->f:nullptr;
            FIberAndThread(Fiber::ptr* f,int thr)
                :thread(thr){
                fiber.swap(*f);
            }

//          构造函数,f:协程执行函数.thr:线程id
            FIberAndThread(std::function<void()> f,int thr)
                :cb(f),thread(thr){

            }
//          构造函数,f:协程执行函数指针,thr:线程id
//          post_satte---->f:nullptr
            FIberAndThread(std::function<void()> *f,int thr)
                :thread(thr){
                cb.swap(*f);
            }
//          无参构造函数
            FIberAndThread()
                :thread(-1){

            }
//      重置数据
            void reset(){
                fiber = nullptr;
                cb = nullptr;
                thread =-1;
            }
        };
    private:
        MutexType m_mutex;
//      线程池
        std::vector<Thread::ptr> m_threads;
//        待执行的协程队列
        std::list<FIberAndThread> m_fibers;
//        std::map<int,std::list<FIberAndThread> > m_thrFibers;
//      use_caller:为true时有效，调度协程
        Fiber::ptr m_rootFiber;
//        协程调度器名称
        std::string m_name;

    protected:
//        协程下的线程id数组
        std::vector<int> m_threadIds;
//        线程数量
        size_t m_threadCount=0;
//        工作线程数量
        std::atomic<size_t> m_activeThreadCount={0};
//        空闲线程数量
        std::atomic<size_t> m_idleThreadCount={0};
//        是否正在停止
        bool m_stopping=true;
//        是否自动停止
        bool m_autoStop=false;
//        主线程id（use_caller）
        int m_rootThread=0;
    };
}



#endif //SERVER_FRAMEWORK_SCHEDULER_H
